using System;
using System.Diagnostics;
using FluentParser.Utils;
using FluentParser.Expressions;

namespace FluentParser.Expressions.Rules.Composition
{
    /// <summary>
    /// This symbol is successful only if the two children symbols are
    /// successfully in a sequence.
    /// </summary>
    /// <example><code>
    /// Symbol left = "Left";
    /// Symbol right = "Right";
    /// Symbol leftAndRight = left + right;
    /// 
    /// leftAndRight.Parse("Left")      --> failure
    /// leftAndRight.Parse("Right")     --> failure
    /// leftAndRight.Parse("LeftRight") --> "LeftRight"
    /// leftAndRight.Parse("RightLeft") --> failure
    /// </code></example>
    [DebuggerDisplay("[GroupSymbolRule {Left} + {Right}]")]
    public class GroupSymbolRule : Symbol
    {
        public Symbol Left { get; private set; }
        public Symbol Right { get; private set; }

        public GroupSymbolRule(Symbol left, Symbol right)
        {
            Left = left;
            Right = right;
            TypeOperation = OperationType.Grouping;
        }

        public override ParsingResult<object> Parse(GrammarContext context, int index)
        {
            ParsingResult<object> value1 = Left.Parse(context, index);
            if (value1 != null)
            {
                ParsingResult<object> value2 = Right.Parse(context, value1.End);
                if (value2 != null)
                    return new ParsingResult<object>(value1.Index, value2.End - value1.End, Tuple.Create(value1.Value, value2.Value));
            }

            return null;
        }

        public override void ParseNode(GrammarContext context, ParsingNodeResult node)
        {
            ParsingNodeResult leftNode = node.AddChild(Left, context);
            if (leftNode.IsSuccess)
            {
                ParsingNodeResult rightNode = node.AddChild(Right, context, leftNode.End);
                if (rightNode.IsSuccess)
                {
                    node.Value = String.Concat(leftNode.Value, rightNode.Value);
                    node.IsSuccess = true;
                }
                else
                {
                    node.Length = 0;
                }
            }
        }
    }
}